﻿using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Neovolve.Extensibility.VisualStudio.ReflectorLink.Tests
{
    /// <summary>
    ///This is a test class for DelegateInvokerTest and is intended
    ///to contain all DelegateInvokerTest Unit Tests
    ///</summary>
    [TestClass]
    public class DelegateInvokerTest
    {
        private const String RunDelegateVoidSleepLengthTestKey = "RunDelegateVoidSleepLengthTestKey";

        private const String RunDelegateVoidTestKey = "RunDelegateVoidTestKey";

        private const String RunDelegateVoidTimeoutSleepLengthTestKey = "RunDelegateVoidTimeoutSleepLengthTestKey";

        private const String RunDelegateVoidTimeoutTestKey = "RunDelegateVoidTimeoutTestKey";

        /// <summary>
        ///A test for InvokeDelegate
        ///</summary>
        [TestMethod]
        [DeploymentItem("Neovolve.Extensibility.ReflectorLink.dll")]
        public void RunDelegateVoidTest()
        {
            DelegateInvoker invoker = new DelegateInvoker();
            const Int32 SleepLength = 2000;

            TestContext.Properties[RunDelegateVoidSleepLengthTestKey] = SleepLength;

            invoker.RunDelegate(DelegateVoidTest);

            Assert.IsTrue(
                (Boolean)TestContext.Properties[RunDelegateVoidTestKey],
                "RunDelegate failed to correctly invoke the method.");
        }

        /// <summary>
        ///A test for InvokeDelegate
        ///</summary>
        [TestMethod]
        [DeploymentItem("Neovolve.Extensibility.ReflectorLink.dll")]
        public void RunDelegateVoidTimeoutPositiveTest()
        {
            DelegateInvoker invoker = new DelegateInvoker();
            const Int32 SleepLength = 2000;
            const Int32 TimeoutLength = 4000;

            TestContext.Properties[RunDelegateVoidTimeoutSleepLengthTestKey] = SleepLength;

            invoker.RunDelegate(DelegateVoidTimeoutTest, TimeoutLength);

            Assert.IsTrue(
                (Boolean)TestContext.Properties[RunDelegateVoidTimeoutTestKey],
                "RunDelegate failed to correctly invoke the method.");
        }

        /// <summary>
        ///A test for InvokeDelegate
        ///</summary>
        [TestMethod]
        [DeploymentItem("Neovolve.Extensibility.ReflectorLink.dll")]
        public void RunDelegateVoidTimeoutNegativeTest()
        {
            DelegateInvoker invoker = new DelegateInvoker();
            const Int32 SleepLength = 6000;
            const Int32 TimeoutLength = 4000;

            TestContext.Properties[RunDelegateVoidTimeoutSleepLengthTestKey] = SleepLength;

            try
            {
                invoker.RunDelegate(DelegateVoidTimeoutTest, TimeoutLength);

                Assert.Fail("TimeoutException was expected but not thrown.");
            }
            catch (TimeoutException ex)
            {
                Assert.IsNotNull(ex, "Failed to correctly throw TimeoutException.");
            }
        }

        #region Helper Methods

        private void DelegateVoidTest()
        {
            Int32 sleepLength = (Int32)TestContext.Properties[RunDelegateVoidSleepLengthTestKey];

            Thread.Sleep(sleepLength);

            TestContext.Properties[RunDelegateVoidTestKey] = true;
        }

        private void DelegateVoidTimeoutTest()
        {
            Int32 sleepLength = (Int32)TestContext.Properties[RunDelegateVoidTimeoutSleepLengthTestKey];

            Thread.Sleep(sleepLength);

            TestContext.Properties[RunDelegateVoidTimeoutTestKey] = true;
        }

        #endregion

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get;
            set;
        }
    }
}